use ash::vk;

use crate::{vulkan::{vk_context, VkContext}, VK_CHECK_UNSAFE, VK_LOGI, VK_LOGP, VK_LOGV};

/// 从candidates里面找到最合适的Format
pub fn find_supported_format(vk_context: &VkContext, candidates: Vec<vk::Format>, tiling: vk::ImageTiling, features: vk::FormatFeatureFlags) -> vk::Format {
    if vk_context.verbose_log {
        for candidate in &candidates {
            let physical_device_format_properties = unsafe {vk_context.vk_instance.get_physical_device_format_properties(vk_context.vk_physical_device, *candidate)};
            VK_LOGV!("physical_device_format_properties {:?}", candidate);
            VK_LOGV!("    {:?}", physical_device_format_properties.linear_tiling_features);
            VK_LOGV!("    {:?}", physical_device_format_properties.optimal_tiling_features);
            VK_LOGV!("    {:?}", physical_device_format_properties.buffer_features);
        }
    }

    for candidate in &candidates {
        let physical_device_format_properties = unsafe {vk_context.vk_instance.get_physical_device_format_properties(vk_context.vk_physical_device, *candidate)};

        match tiling {
            vk::ImageTiling::LINEAR => {
                if (physical_device_format_properties.linear_tiling_features & features) == features { return *candidate; }
            },
            vk::ImageTiling::OPTIMAL => {
                if (physical_device_format_properties.optimal_tiling_features & features) == features { return *candidate; }
            },
            _ => {}
        }
    }

    VK_LOGP!("Failed to find supported format!")
}

pub fn find_depth_format(vk_context: &VkContext) -> vk::Format {
    find_supported_format(vk_context, 
        vec![vk::Format::D32_SFLOAT, vk::Format::D32_SFLOAT_S8_UINT, vk::Format:: D24_UNORM_S8_UINT], 
        vk::ImageTiling::OPTIMAL,
        vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT)
}

pub fn has_stencil_component(format: &vk::Format) -> bool {
    format == &vk::Format::D32_SFLOAT_S8_UINT || format == &vk::Format::D24_UNORM_S8_UINT
}

/// required_bits是我们申请内存时的Flags
/// supported_bits是内存get_buffer_memory_requirements返回的数据
/// 其中supported_bits是独热码，每个对应一组Flags组合，也就是去device上找同时满足这两个条件的memory type
/// 可以打开verbose_log查看对应打印的Log详情
pub fn find_memory_type(vk_context: &VkContext, required_bits: &vk::MemoryPropertyFlags, supported_bits: u32) -> u32 {
    let physical_device_memory_properties = unsafe{ vk_context.vk_instance.get_physical_device_memory_properties(vk_context.vk_physical_device) };

    if vk_context.verbose_log {
        VK_LOGI!("{:?} - {}", required_bits, supported_bits);
        for memory_type_index in 0..physical_device_memory_properties.memory_type_count as usize {
            VK_LOGI!("{} : {:?}", memory_type_index, physical_device_memory_properties.memory_types[memory_type_index].property_flags)
        }
    }
    
    for memory_type_index in 0..physical_device_memory_properties.memory_type_count as usize {
        if (supported_bits & (1 << memory_type_index) != 0) && (physical_device_memory_properties.memory_types[memory_type_index].property_flags & *required_bits == *required_bits) {
            return memory_type_index as u32;
        }
    }

    VK_LOGP!("Failed to find suitable memory type!");
}